home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
The Fatted Calf
/
The Fatted Calf.iso
/
Applications
/
Graphics
/
NXPlot3d
/
Source
/
PControl.m
< prev
next >
Wrap
Text File
|
1994-02-18
|
16KB
|
610 lines
#import "PControl.h"
#import "Plot3DView.h"
#import "PlotShape.h"
#import <appkit/appkit.h>
#import <dpsclient/event.h>
#import <dpsclient/psops.h>
#import <appkit/color.h>
#import <stdio.h>
#import <math.h>
#import <ctype.h>
#include <libc.h>
#import "Expression.h"
#import "DensView.h"
int comp(float *x,float *y);
@implementation PControl
-init
{
[super init];
return self;
}
/* Called once by the Plot3DView to do initialization and pass pref pointer */
-startup:(SetPref *)Pref
{
pref=Pref;
/* display initial preferences settings */
curPref=0;
bpath=(char *)[[NXBundle mainBundle] directory];
[symsel selectCellWithTag:pref[0].sym+1];
equation=[equation docView];
[equation setText:[pref[0].expr text]];
/* make sure plot agrees with displayed min/max values */
[gridx setIntValue:pref[curPref].nx];
[gridy setIntValue:pref[curPref].ny];
[d3View zoomTo:[minX floatValue] :[minY floatValue] :[maxX floatValue] :[maxY floatValue]];
[d3View setDelegate:self];
/*[self readFile:self];*/
I_lim=[I_lim contentView];
I_dis=[I_dis contentView];
I_pho=[I_pho contentView];
return self;
}
/* display preferences for a data set */
-disPref:sender
{
int i;
curPref=[[sender selectedCell] tag];
[symsel selectCellWithTag:pref[curPref].sym+1];
[color1 setColor:NXConvertRGBToColor(pref[curPref].mapcol[0][0],
pref[curPref].mapcol[0][1],pref[curPref].mapcol[0][2])];
[color2 setColor:NXConvertRGBToColor(pref[curPref].mapcol[1][0],
pref[curPref].mapcol[1][1],pref[curPref].mapcol[1][2])];
[color3 setColor:NXConvertRGBToColor(pref[curPref].mapcol[2][0],
pref[curPref].mapcol[2][1],pref[curPref].mapcol[2][2])];
[color4 setColor:NXConvertRGBToColor(pref[curPref].mapcol[3][0],
pref[curPref].mapcol[3][1],pref[curPref].mapcol[3][2])];
[color5 setColor:NXConvertRGBToColor(pref[curPref].mapcol[4][0],
pref[curPref].mapcol[4][1],pref[curPref].mapcol[4][2])];
[colortype selectCellWithTag:pref[curPref].mapmode];
for (i=0; i<5; i++)
[[colorsel cellAt:0 :i] setIntValue:pref[curPref].mapsel[i]];
if (pref[curPref].fileData==NULL) [ffSel selectCellWithTag:0];
else [ffSel selectCellWithTag:1];
[equation setText:[pref[curPref].expr text]];
[gridx setIntValue:pref[curPref].nx];
[gridy setIntValue:pref[curPref].ny];
[d3View zoom:self];
return self;
}
/* put preferences from screen into SetPref for curPref set */
-stoPref:sender
{
char *tmp;
int i,j,k;
pref[curPref].sym=[[symsel selectedCell] tag]-1;
pref[curPref].nx=[gridx intValue];
if (pref[curPref].nx>MAXGRID||pref[curPref].nx<4)
[gridx setIntValue:pref[curPref].nx=10];
pref[curPref].ny=[gridy intValue];
if (pref[curPref].ny>MAXGRID||pref[curPref].ny<4)
[gridy setIntValue:pref[curPref].ny=10];
tmp=malloc([equation textLength]+50);
[equation getSubstring:tmp start:0 length:[equation textLength]+1];
/* Fix equation for parsing */
k=strlen(tmp);
for (i=0; i<k; i++) {
if (tmp[i]=='[') tmp[i]='(';
if (tmp[i]==']') tmp[i]=')';
if (isupper(tmp[i])) tmp[i]=tolower(tmp[i]);
if ((tmp[i]=='+'||tmp[i]=='-')&&(isdigit(tmp[i+1])||tmp[i+1]=='.')) {
for (j=k; j>i; j--) tmp[j+1]=tmp[j];
tmp[i+1]=' ';
k++;
}
}
/* if the equation doesn't parse, set it to 0 */
if (strlen(tmp)==0 ||
[pref[curPref].expr parse:tmp]==0) {
[self error:"Cannot parse equation!"];
[pref[curPref].expr parse:"0"];
}
/* Colors */
NXConvertColorToRGB([color1 color],&pref[curPref].mapcol[0][0],
&pref[curPref].mapcol[0][1],&pref[curPref].mapcol[0][2]);
NXConvertColorToRGB([color2 color],&pref[curPref].mapcol[1][0],
&pref[curPref].mapcol[1][1],&pref[curPref].mapcol[1][2]);
NXConvertColorToRGB([color3 color],&pref[curPref].mapcol[2][0],
&pref[curPref].mapcol[2][1],&pref[curPref].mapcol[2][2]);
NXConvertColorToRGB([color4 color],&pref[curPref].mapcol[3][0],
&pref[curPref].mapcol[3][1],&pref[curPref].mapcol[3][2]);
NXConvertColorToRGB([color5 color],&pref[curPref].mapcol[4][0],
&pref[curPref].mapcol[4][1],&pref[curPref].mapcol[4][2]);
for (i=0; i<5; i++) pref[curPref].mapsel[i]=[[colorsel cellAt:0 :i] intValue];
pref[curPref].mapmode=[[colortype selectedCell] tag];
/* if spherical plot, set proper limits */
if (pref[curPref].sym==6) {
[minX setFloatValue:0];
[maxX setFloatValue:M_PI];
[minY setFloatValue:0];
[maxY setFloatValue:M_PI*2.0];
[self setMinMax:self];
}
[d3View zoom:self];
return self;
}
/* Read 3d data from a file and put it into the current data set */
/* does NOT wait for an "OK" press, like other prefs */
-readFile:sender
{
id panel;
int i,j,k,cc=0,nx,ny;
char s[201],sc[20];
FILE *in;
float x0,y0,z0,z1,f,x[MAXGRID+1],y[MAXGRID+1];
Point *p;
if (pref[curPref].fileData!=NULL) { free(pref[curPref].fileData); pref[curPref].
fileData=NULL; }
if (sender!=self) {
/* get a filespec from the user */
panel=[[OpenPanel new] allowMultipleFiles:NO];
if (![panel runModalForTypes:NULL]) {
[ffSel selectCellWithTag:0];
[equation setText:"0"];
[pref[curPref].expr parse:"0"];
return self;
}
/* if we can't open the file, go back to equation mode */
in=fopen([panel filename],"r");
}
else {
[ffSel selectCellWithTag:1];
sprintf(s,"%s/title.3d",bpath);
in=fopen(s,"r");
}
if (fgets(s,200,in)==NULL) {
[ffSel selectCellWithTag:0];
[equation setText:"0"];
[pref[curPref].expr parse:"0"];
[self error:"Can't open file."];
return self;
}
/* ignore leading # lines */
while (s[0]=='#') { fgets(s,80,in); cc++; }
/* accept either "x,y,z\n" or "x y z\n" files */
strcpy(sc," %f , %f , %f");
if (sscanf(s,sc,&x[0],&y[0],&z0)!=3) {
strcpy(sc," %f %f %f");
if (sscanf(s,sc,&x[0],&y[0],&z0)!=3) {
[ffSel selectCellWithTag:0];
[equation setText:"0"];
[pref[curPref].expr parse:"0"];
[self error:"File not in 'x y z' or 'x,y,z' format."];
return self;
}
}
z1=z0;
/* count the number of points in the file */
nx=ny=1;
while (fscanf(in,sc,&x[nx],&y[ny],&f)==3) {
if (f<z0) z0=f;
for (i=0; i<nx; i++) if (x[nx]==x[i]) break;
if (i==nx) nx++;
for (i=0; i<ny; i++) if (y[ny]==y[i]) break;
if (i==ny) ny++;
if (nx==MAXGRID+1||ny==MAXGRID+1) {
[ffSel selectCellWithTag:0];
[equation setText:"0"];
[pref[curPref].expr parse:"0"];
[self error:"More than MAXGRID points in x or y."];
fclose(in);
return self;
}
}
qsort(x,nx,sizeof(float),comp);
qsort(y,ny,sizeof(float),comp);
rewind(in);
/* 2nd pass, allocate memory,initialize and read data into array */
p=pref[curPref].fileData=malloc(sizeof(Point)*nx*ny);
pref[curPref].nfdata=nx*ny;
for (i=0; i<nx; i++) {
for (j=0; j<ny; j++) {
p[i+nx*j].x=x[i];
p[i+nx*j].y=y[j];
p[i+nx*j].z=z0;
}
}
for (i=0; i<cc; i++) fgets(s,240,in);
while (fscanf(in,sc,&x0,&y0,&f)==3) {
for (j=0; j<nx; j++) if (x0==x[j]) break;
for (k=0; k<ny; k++) if (y0==y[k]) break;
if (k==ny||j==nx) [self error:"Unusual error, notify author."];
p[j+nx*k].z=f;
}
if (pref[curPref].data!=NULL) free(pref[curPref].data);
pref[curPref].data=malloc(sizeof(Point)*pref[curPref].nfdata);
pref[curPref].color=malloc(sizeof(RtColor)*pref[curPref].nfdata);
[minX setFloatValue:x[0]];
[minY setFloatValue:y[0]];
[maxX setFloatValue:x[nx-1]];
[maxY setFloatValue:y[ny-1]];
/* equation is now used to modify data Z values, set initial formula for */
/* z(x,y,z)=z. ie - for log plots you would enter "log(z)" */
[equation setText:"z"];
[pref[curPref].expr parse:"z"];
/* update the display */
[self setMinMax:self];
[d3View zoom:self];
return self;
}
/* return a data set to equation mode, free memory used by the file */
-clearFile:sender
{
if (pref[curPref].fileData!=NULL) { free(pref[curPref].fileData); pref[curPref].fileData=NULL; }
pref[curPref].nfdata=0;
[equation setText:"0"];
[pref[curPref].expr parse:"0"];
[d3View zoom:self];
return(self);
}
/* minz and maxz can be modified before returning, but currently aren't */
-minmaxZ:(float *)minz :(float *)maxz
{
[dminZ setFloatValue:*minz];
[dmaxZ setFloatValue:*maxz];
if ([dzSwitch intValue]) {
[minZ setFloatValue:*minz];
[maxZ setFloatValue:*maxz];
}
*minz=[minZ floatValue];
*maxz=[maxZ floatValue];
return self;
}
/* display new min/max values (does not inform the views of the change) */
-setMM:(float)minx :(float)maxx :(float)miny :(float)maxy
{
[minX setFloatValue:minx];
[minY setFloatValue:miny];
[maxX setFloatValue:maxx];
[maxY setFloatValue:maxy];
return self;
}
/* Tell the Plot3DView and (indirectly) the DensView about new max/min vals */
-setMinMax:sender
{
[d3View zoomTo:[minX floatValue] :[minY floatValue] :[maxX floatValue] :[maxY floatValue]];
[d3View zoom:self];
return self;
}
/* zoom in by a fixed amount */
-zoomIn:sender
{
float x,y,x1,y1;
x1=[maxX floatValue];
x=[minX floatValue];
y1=[maxY floatValue];
y=[minY floatValue];
[maxX setFloatValue:x1-(x1-x)/4.0];
[minX setFloatValue:x+(x1-x)/4.0];
[maxY setFloatValue:y1-(y1-y)/4.0];
[minY setFloatValue:y+(y1-y)/4.0];
[self setMinMax:self];
[d3View zoom:self];
return self;
}
/* zoom out by a fixed amount */
-zoomOut:sender
{
float x,y,x1,y1;
x1=[maxX floatValue];
x=[minX floatValue];
y1=[maxY floatValue];
y=[minY floatValue];
[maxX setFloatValue:x1+(x1-x)/4.0];
[minX setFloatValue:x-(x1-x)/4.0];
[maxY setFloatValue:y1+(y1-y)/4.0];
[minY setFloatValue:y-(y1-y)/4.0];
[self setMinMax:self];
[d3View zoom:self];
return self;
}
/* sent by DensView, min/max are from 0.0 to 1.0, not real units */
-zoomTo:(float)minx :(float)miny :(float)maxx :(float)maxy
{
float x0,x1,y0,y1;
x0=[minX floatValue];
x1=[maxX floatValue];
y0=[minY floatValue];
y1=[maxY floatValue];
[minX setFloatValue:x0+(x1-x0)*minx];
[minY setFloatValue:y0+(y1-y0)*miny];
[maxX setFloatValue:x0+(x1-x0)*maxx];
[maxY setFloatValue:y0+(y1-y0)*maxy];
[self setMinMax:self];
[d3View zoom:self];
return self;
}
-dumpContour
{
[dView saveTiff:self];
return self;
}
/* update the density plot */
-updDen:(RtPoint)TickO :(RtPoint)TickS
{
static float *densData=NULL;
static int ndd=0;
int k,i,nx,ny;
NXRect rec,rec2,tick;
float x0=0,x1=0,y0=0,y1=0,zlim[4] = { -1.0,1.0,0,0};
char s[80];
float lev0,lev1;
zlim[2]=[minZ floatValue];
zlim[3]=[maxZ floatValue];
if ([autoCont intValue]) {
i=[[levels cellAt:2 :0] intValue];
lev1=2.0/(float)i;
lev0= -1.0+lev1/2.0;
[[levels cellAt:0 :0] setFloatValue:(lev0+1.0)/2.0*
(zlim[3]-zlim[2])+zlim[2]];
[[levels cellAt:1 :0] setFloatValue:lev1/2.0*
(zlim[3]-zlim[2])];
}
else {
lev0=[[levels cellAt:0 :0] floatValue];
lev1=[[levels cellAt:1 :0] floatValue];
lev0=(lev0-zlim[2])/(zlim[3]-zlim[2])*2.0-1.0;
lev1=lev1/(zlim[3]-zlim[2])*2.0;
}
if (lev1<=0) lev1=.2;
[[d3View worldShape] setContour:lev0/2.0+.5 :lev1/2.0];
tick.origin.x=(TickO[0]+1.0)/2.0;
tick.origin.y=(TickO[1]+1.0)/2.0;
tick.size.width=TickS[0]/2.0;
tick.size.height=TickS[1]/2.0;
rec2.origin.x=[minX floatValue];
rec2.origin.y=[minY floatValue];
rec2.size.width=[maxX floatValue]-[minX floatValue];
rec2.size.height=[maxY floatValue]-[minY floatValue];
rec=rec2;
if (pref[curPref].ndata==0) {
[dView setData:0 :0 :NULL :zlim :tick :rec :rec2 :lev0 :lev1];
return self;
}
nx=pref[curPref].nx;
ny=pref[curPref].ny;
if (ndd<(nx*ny)) {
if (densData!=NULL) free(densData);
densData=malloc(nx*ny*sizeof(float));
ndd=nx*ny;
}
if (pref[curPref].fileData==NULL||nx*ny==pref[curPref].ndata) {
for (k=0; k<pref[curPref].ndata; k++) densData[k]=pref[curPref].data[k].z;
}
else {
sprintf(s,"Error nx*ny=%d ndata=%d\n",nx*ny,pref[curPref].ndata);
[self error:s];
/* for (k=0; k<(nx*ny); k++) densData[k]= -.5;
for (k=0; k<pref[curPref].ndata; k++) {
i=floor((pref[curPref].data[k].x+.5)*(float)nx)+
floor((pref[curPref].data[k].y+.5)*(float)ny)*nx;
if (i>=0 && i<ndd) densData[i]=pref[curPref].data[k].z;
}*/
}
if (pref[curPref].fileData!=NULL) {
for (i=0; i<pref[curPref].nfdata; i++) {
x0=pref[curPref].fileData[i].x;
y0=pref[curPref].fileData[i].y;
if (x0>=rec2.origin.x && y0>=rec2.origin.y) break;
}
for (i=pref[curPref].nfdata-1; i>=0; i--) {
x1=pref[curPref].fileData[i].x;
y1=pref[curPref].fileData[i].y;
if (x1<=rec2.origin.x+rec2.size.width &&
y1<=rec2.origin.y+rec2.size.height) break;
}
rec.size.width=x1-x0;
rec.origin.x=x0;
rec.size.height=y1-y0;
rec.origin.y=y0;
}
if (pref[curPref].sym!= -1) [dView setData:nx :ny :densData :zlim :tick :rec :rec2 :lev0 :lev1];
else [dView setData:0 :0 :NULL :zlim :tick :rec :rec2 :lev0 :lev1];
return self;
}
int comp(float *x,float *y)
{
if (x<y) return(-1);
if (y>x) return(1);
return (0);
}
-newInsp:sender
{
int i;
i=[[sender selectedCell] tag];
switch(i) {
case 0: [I_BOX setContentView:I_lim];
break;
case 1: [I_BOX setContentView:I_dis];
break;
case 2: [I_BOX setContentView:I_pho];
break;
}
[I_BOX display];
return self;
}
/* variable slider changed */
-setVarS:sender
{
int i;
for (i=0; i<5; i++)
[[varText cellAt:i :0] setFloatValue:[[varSli cellAt:i :0] floatValue]];
[d3View zoom:self];
return self;
}
/* variable text changed */
-setVarT:sender
{
int i;
for (i=0; i<5; i++)
[[varSli cellAt:i :0] setFloatValue:[[varText cellAt:i :0] floatValue]];
[d3View zoom:self];
return self;
}
/* new var min/max */
-setVarMinMax:sender
{
int i;
for (i=0; i<5; i++)
[[[varSli cellAt:i :0] setMaxValue:[[varMax cellAt:i :0] floatValue]] setMinValue:[[varMin cellAt:i :0] floatValue]];
return self;
}
-saveData:sender
{
id pan;
FILE *out;
int i;
float x0,x1,y0,y1,z0,z1;
x0=[minX floatValue];
x1=[maxX floatValue]-x0;
y0=[minY floatValue];
y1=[maxY floatValue]-y0;
z0=[minZ floatValue];
z1=[maxZ floatValue]-z0;
pan=[SavePanel new];
if ([pan runModal]) {
out=fopen([pan filename],"w");
fprintf(out,"# Created by Plot3D\n");
for (i=0; i<pref[curPref].ndata; i++)
fprintf(out,"%f\t%f\t%f\n",(pref[curPref].data[i].x/2.0+.5)*x1+x0,
(pref[curPref].data[i].y/2.0+.5)*y1+y0,
(pref[curPref].data[i].z/2.0+.5)*z1+z0);
fclose(out);
}
return self;
}
/* Start rendering an animation */
-makeAnim:sender
{
int afl=0,n=16,cf;
static id savePanel=nil;
float chi,chistp,theta,t,tstp;
char animFile[100]; /* animation directory */
char animName[30]; /* animation name */
char fsp[MAXPATHLEN];
int i,j=0;
if (!savePanel) {
savePanel=[SavePanel new];
[savePanel setRequiredFileType:"anim"];
}
if(![savePanel runModal]) return self;
if (strlen([savePanel filename])>78) {
[self error:"Filespec too long. Please notify author."];
return self;
}
strcpy(animFile, [savePanel filename]);
mkdir(animFile,0777);
for (i=strlen(animFile)-1; i>=0; i--) if (animFile[i]=='/') break;
i++;
while (i<strlen(animFile)-5) animName[j++]=animFile[i++];
animName[j]=0;
afl=[[animFlag cellAt:0 :0] intValue]*ANIM_spin+
[[animFlag cellAt:1 :0] intValue]*ANIM_t;
if (afl==0) {
[self error:"Animation doesn't do anything!"];
return self;
}
n=[animFrames intValue];
chistp=M_PI*2.0/(float)n;
chi=[d3View getChi];
theta=[d3View getTheta];
t=[[varMin cellAt:0 :0] floatValue];
tstp=([[varMax cellAt:0 :0] floatValue]-t)/(float)(n-1);
for (cf=0; cf<n; cf++) {
[[varText cellAt:0 :0] setFloatValue:t];
[[varSli cellAt:0 :0] setFloatValue:t];
[d3View setAng:theta :chi];
[d3View zoom:self];
sprintf(fsp,"%s/%s.%d.tiff",animFile,animName,cf+1);
[self message:"Rendering animation. This will take a while ..." :fsp];
[d3View renderTIFF:fsp];
if (afl&ANIM_t) t+=tstp;
if (afl&ANIM_spin) chi+=chistp;
}
[self message:"Rendering complete !!!" :"(use Movie.app or a similar program to view)"];
return self;
}
-error:(char *)msg
{
[errTitle setStringValue:"ERROR"];
[errMsg setStringValue:msg];
[errPan makeKeyAndOrderFront:self];
return self;
}
-message:(char *)s1 :(char *)s2
{
[errTitle setStringValue:s1];
[errMsg setStringValue:s2];
[errPan makeKeyAndOrderFront:self];
return self;
}
@end